/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.seari.pa;

import com.seari.bean.BaseClient;
import com.seari.bean.pa.PaHeader;
import com.seari.bean.pa.PaInstruct;
import com.seari.bean.pa.PaResponse;
import com.seari.pa.exception.BodyOutOfRangeException;
import com.seari.pa.handler.PaClientHandler;
import com.seari.pa.handler.PaDecoder;
import com.seari.pa.handler.PaTimer;
import com.seari.utils.DataUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.GenericFutureListener;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Rainbow
 */
public class PaClient extends BaseClient {
	// 地址
	private String host;
	// 端口
	private int port;
	// 流通道
	private Channel channel;
	// 线程时间
	private PaTimer timer;

	// pa响应集
	public final List<PaResponse> responseList = new ArrayList<>();
	public final List<PaResponse> stopResponseList = new ArrayList<>();
	protected static Logger logger = LoggerFactory.getLogger(PaClient.class);

	public PaClient() {
		super();
	}

	public PaClient(String host, int port) {
		this.host = host;
		this.port = port;
	}

	@Override
	public void setup() throws InterruptedException {
		// workerGroup处理已经被接收的连接
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		PaClient client = this;
		try {
			// Bootstrap是一个启动 NIO 服务的辅助启动类
			Bootstrap b = new Bootstrap();
			b.group(workerGroup);
			// 使用NioSocketChannel类的新的channel接收进来的连接
			b.channel(NioSocketChannel.class);
			// option() 是提供给NioSocketChannel用来接收进来的连接
			b.option(ChannelOption.SO_KEEPALIVE, true);

			// 处理最近接收的channel
			b.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				public void initChannel(SocketChannel ch) throws Exception {
					// 解码器
					ch.pipeline().addLast("paDecoder", new PaDecoder());
					
					// 处理器
					ch.pipeline().addLast(new PaClientHandler(client));

				}
			});
			// Start the client. 绑定端口然后启动服务
			ChannelFuture f = b.connect(host, port).sync();

			channel = f.channel();
			// if(f.isSuccess())
			// {
			// System.out.println("连接成功");
			// }else{
			// System.out.println("连接失败 尝试重连");
			// run();
			// }
			// Wait until the connection is closed.
			if (f.isSuccess()) {
				logger.info("连接成功");
				System.out.println(" client..... : " + client.toString());
			}
			// f.channel().closeFuture().sync();
			f.channel().closeFuture()
					.addListener(new GenericFutureListener<ChannelFuture>() {
						@Override
						public void operationComplete(ChannelFuture f)
								throws Exception {
							workerGroup.shutdownGracefully();
						}
					});
		} catch (Exception ex) {
			logger.warn(ex.getMessage());
		}
		// finally {
		// workerGroup.shutdownGracefully();
		// }
	}

	/**
	 * 发送不符合帧
	 * 
	 */
	public void sendNoAnswerFrame() {
		ByteBuf byteBuf = null;
		byteBuf = channel.alloc().buffer(6 * 4);
		byteBuf.writeBytes(PaHelper.PA_HEADER);
		byteBuf.writeByte(0x30);
		byteBuf.writeByte(0);
		byteBuf.writeByte(0);
		byteBuf.writeByte((byte) (0x30));
		logger.info("send no answer frame");
		channel.writeAndFlush(byteBuf);
	}

	// 发送pa 帧
	public void sendPaFrame(PaResponse paResponse) throws Exception {
		ByteBuf byteBuf = null;
		byteBuf = channel.alloc().buffer(24 * 4);
		byteBuf.writeBytes(PaHelper.PA_HEADER);
		byteBuf.writeByte(0x31);
		byteBuf.writeByte(paResponse.stationNum);
		byteBuf.writeByte(paResponse.paNum&0xff);
		byteBuf.writeByte(paResponse.chk);
		logger.info(
				"send pa frame {}",
				DataUtil.BytesToHexStr(new byte[] { (byte) 0xeb, (byte) 0x90,
						0x31, (byte) paResponse.stationNum,
						(byte) paResponse.paNum, (byte) paResponse.chk }));
		channel.writeAndFlush(byteBuf);
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public Channel getChannel() {
		return channel;
	}

	public void setChannel(Channel channel) {
		this.channel = channel;
	}

	public PaTimer getTimer() {
		return timer;
	}

	public void setTimer(PaTimer timer) {
		this.timer = timer;
	}

	@Override
	public void reset() throws Exception {
		PaTimer timer = this.getTimer();
		if (null != timer) {
			timer.setTerminate(true);
		}
	}

}
